﻿/* 
 * This file is part of marvellous-components project.
 * 
 * The marvellous-components is free software: you can redistribute it 
 * and/or modify it under the terms of the GNU General Public License 
 * version 3 as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Drawing;
using marvellous_components.LuxuriousMonthCalendar;

/*
 * 
 * Keyboard shortcuts in this class:
 *  Insert - add new report
 *  Delete - delete selected report
 *  Enter  - edit selected report
 *  
 * Mouse shortcuts in this class:
 *  Double Click on row - edit the row
 *  Click on (0,0) cell - create new row
 *  
 */
namespace marvellous_components.MagnificentTimeReportDataGridView
{
    /// <summary>
    /// This is DataGridView, which displays RowData objects. Consist of 5 columns:
    ///  - date (i.e. the day to create report for)
    ///  - time (i.e. amount of hours and minutes to report in specific day)
    ///  - desc1, desc2, desc3 (three customizable fields)
    /// 
    /// Must be initialized with InitializeDateTime method.
    /// 
    /// Following parameters are customizable:
    ///  - colours of cells (overtimed, incomplete time, valid)
    ///  - column headers
    ///  - default workday length
    /// 
    /// Must be initialized with InitializeAwesomeTextbox method.
    /// </summary>
    public class MagnificentTimeReportDataGridView : DataGridView 
    {

        private RowDataEditorFactory editorFactory = null;

        private LuxuriousMonthCalendar.LuxuriousMonthCalendar miniCalendar = null;

        private bool keyDownFlag = false;

        private Color colourOkCell = Color.FromArgb(120, 255, 120);
        private Color colourOvertimeCell = Color.FromArgb(255, 120, 120);
        private Color colourIncompleteCell = Color.FromArgb(255, 255, 120);

        private int defaultWorkTimeHours = 8;
        private int defaultWorkTimeMinutes = 0;

        private string columnNameDate, columnNameTime, columnNameDesc1, columnNameDesc2, columnNameDesc3, columnNameModified;

        private string confirmDeleteDialogCaption = "Confirmation";
        private string confirmDeleteDialogText = "Do you really want to delete row?";


        #region GettersAndSetters
        /// <summary>
        /// Amount of hours in valid workday.
        /// This will be:
        ///  - default value for new reports
        ///  - value used in checking if amount of time reported on specific day is valid
        /// </summary>
        public int DefaultWorkTimeHours
        {
            get { return defaultWorkTimeHours; }
            set { defaultWorkTimeHours = value; }
        }
        
        /// <summary>
        /// Amount of minutes in valid workday.
        /// This will be:
        ///  - default value for new reports
        ///  - value used in checking if amount of time reported on specific day is valid
        /// </summary>
        public int DefaultWorkTimeMinutes
        {
            get { return defaultWorkTimeMinutes; }
            set { defaultWorkTimeMinutes = value; }
        }

        /// <summary>
        /// Colour of cell which represents day with valid amount of time.
        /// </summary>
        public Color ColourOkCell
        {
            get { return colourOkCell; }
            set { colourOkCell = value; }
        }       

        /// <summary>
        /// Colour of cell which represents day with too much amount of time.
        /// </summary>
        public Color ColourOvertimeCell
        {
            get { return colourOvertimeCell; }
            set { colourOvertimeCell = value; }
        }       

        /// <summary>
        /// Colour of cell which represents day with too little amount of time.
        /// </summary>
        public Color ColourIncompleteCell
        {
            get { return colourIncompleteCell; }
            set { colourIncompleteCell = value; }
        }

        /// <summary>
        /// Date column header.
        /// </summary>
        public string ColumnNameDate
        {
            get { return columnNameDate; }
            set { columnNameDate = value; }
        }

        /// <summary>
        /// Time column header.
        /// </summary>
        public string ColumnNameTime
        {
            get { return columnNameTime; }
            set { columnNameTime = value; }
        }

        /// <summary>
        /// Desc1 column header
        /// </summary>
        public string ColumnNameDesc1
        {
            get { return columnNameDesc1; }
            set { columnNameDesc1 = value; }
        }

        /// <summary>
        /// Desc2 column header
        /// </summary>
        public string ColumnNameDesc2
        {
            get { return columnNameDesc2; }
            set { columnNameDesc2 = value; }
        }

        /// <summary>
        /// Desc3 column header
        /// </summary>
        public string ColumnNameDesc3
        {
            get { return columnNameDesc3; }
            set { columnNameDesc3 = value; }
        }

        /// <summary>
        /// Modified column header
        /// </summary>
        public string ColumnNameModified
        {
            get { return columnNameModified; }
            set { columnNameModified = value; }
        }

        /// <summary>
        /// Caption of delete confirmation dialog
        /// </summary>
        public string ConfirmDeleteDialogCaption
        {
            get { return confirmDeleteDialogCaption; }
            set { confirmDeleteDialogCaption = value; }
        }

        /// <summary>
        /// Text of delete confirmation dialog
        /// </summary>
        public string ConfirmDeleteDialogText
        {
            get { return confirmDeleteDialogText; }
            set { confirmDeleteDialogText = value; }
        }
        #endregion GettersAndSetters

        /// <summary>
        /// Method must be invoked in order to prepare columns and initialize data.
        /// </summary>
        /// <param name="editorFactory">Class which prepares RowDataEditor. RowDataEditor is invoked when user wants to edit the field. Use "null" for readonly tables.</param>
        /// <param name="availableReports">Initial rows. Use "null" for empty table.</param>
        public void InitializeDateTime(RowDataEditorFactory editorFactory, RowData[] availableReports)
        {
            if (editorFactory != null)
            {
                this.editorFactory = editorFactory;
            }
            else
            {
                this.editorFactory = new ReadOnlyRowDataEditorFactory();
            }
            this.ColumnDate = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.ColumnTime = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.ColumnDescription1 = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.ColumnDescription2 = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.ColumnDescription3 = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.ColumnModified = new System.Windows.Forms.DataGridViewTextBoxColumn();
            // 
            // ColumnDate
            //
            DataGridViewCellStyle columnDateStyle = new DataGridViewCellStyle();
            columnDateStyle.Format = "yyyy-MM-dd (ddd)";
            this.ColumnDate.DefaultCellStyle = columnDateStyle;
            this.ColumnDate.HeaderText = columnNameDate;
            this.ColumnDate.Name = "ColumnDate";
            this.ColumnDate.ReadOnly = true;
            // 
            // ColumnTime
            // 
            this.ColumnTime.HeaderText = columnNameTime;
            this.ColumnTime.Name = "ColumnTime";
            this.ColumnTime.ReadOnly = true;
            // 
            // ColumnDescription1
            // 
            this.ColumnDescription1.HeaderText = columnNameDesc1;
            this.ColumnDescription1.Name = "ColumnDescription1";
            this.ColumnDescription1.ReadOnly = true;
            // 
            // ColumnDescription2
            // 
            this.ColumnDescription2.HeaderText = columnNameDesc2;
            this.ColumnDescription2.Name = "ColumnDescription2";
            this.ColumnDescription2.ReadOnly = true;
            // 
            // ColumnDescription3
            // 
            this.ColumnDescription3.HeaderText = columnNameDesc3;
            this.ColumnDescription3.Name = "ColumnDescription3";
            this.ColumnDescription3.ReadOnly = true;
            //
            // ColumnModified
            //
            this.ColumnModified.HeaderText = columnNameModified;
            this.ColumnModified.Name = "ColumnModified";
            this.ColumnModified.ReadOnly = true;

            this.AllowUserToAddRows = false;
            this.AllowUserToResizeRows = false;
            this.MultiSelect = false;
            this.SelectionMode = DataGridViewSelectionMode.CellSelect;
            this.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
            this.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
            this.ColumnDate,
            this.ColumnTime,
            this.ColumnDescription1,
            this.ColumnDescription2,
            this.ColumnDescription3,
            this.ColumnModified});

            this.CellDoubleClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.this_CellDoubleClick);
            this.CellClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.this_CellClick);
            this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.this_KeyUp);
            this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.this_KeyDown);
            this.RowsRemoved += new System.Windows.Forms.DataGridViewRowsRemovedEventHandler(this.this_RowsRemoved);

            if (availableReports != null)
            {
                foreach (RowData rd in availableReports)
                {
                    putRowDataInRow(rd, -1);
                }
            }
            else
            {
                this.ColumnModified.Visible = false;
            }
        }


        public void InitializeMiniCalendar(LuxuriousMonthCalendar.LuxuriousMonthCalendar miniCalendar)
        {
            this.miniCalendar = miniCalendar;
            miniCalendar.InitCalendar(new DataGridViewCellEventHandler(LuxuriousMonthCalendar_CellClick));
        }

        private void LuxuriousMonthCalendar_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            RowDataEditor editor = editorFactory.createRowDataEditor();
            RowData sr = new RowData(defaultWorkTimeHours, defaultWorkTimeMinutes).changeDate(miniCalendar.getDate(e.RowIndex,e.ColumnIndex));
            sr = editor.ShowDialog(sr);
            putRowDataInRow(sr, -1);
            updateColours();
        }

        public RowData[] getReport()
        {
            RowData[] result = new RowData[this.Rows.Count];
            for (int i = 0; i < result.Length; i++)
            {
                result[i] = (RowData)this.Rows[i].Cells[5].Value; 
            }
            return result;
        }

        private void this_RowsRemoved(object sender, DataGridViewRowsRemovedEventArgs e)
        {
            updateColours();
        }


        private void updateColours() 
        {
            Hashtable ht = new Hashtable();
            for (int i = 0; i < this.Rows.Count; i++)
            {
                DataGridViewCellCollection cells = this.Rows[i].Cells;
                string key = cells[0].Value.ToString();

                WorkTime wt;
                if (ht.Contains(key))
                {
                    wt = (WorkTime)ht[key];
                    ht.Remove(key);
                }
                else
                {
                    wt = new WorkTime(0, 0);
                }
                wt = wt.Add((WorkTime)cells[1].Value);
                ht.Add(key, wt);
            }
            List<HighlightedDate> dates = new List<HighlightedDate>();

            for (int i = 0; i < this.Rows.Count; i++)
            {
                DataGridViewCellCollection cells = this.Rows[i].Cells;
                string key = cells[0].Value.ToString();
                WorkTime wt = (WorkTime)ht[key];

                System.Drawing.Color rowColour;
                if (wt.Hours == defaultWorkTimeHours)
                {
                    if (wt.Minutes == defaultWorkTimeMinutes)
                    {
                        rowColour = ColourOkCell;
                    }
                    else if (wt.Minutes > defaultWorkTimeMinutes)
                    {
                        rowColour = ColourOvertimeCell;
                    }
                    else 
                    {
                        rowColour = ColourIncompleteCell;
                    }
                }
                else if (wt.Hours > defaultWorkTimeHours)
                {
                    rowColour = ColourOvertimeCell;
                }
                else
                {
                    rowColour = ColourIncompleteCell;
                }
                dates.Add(new HighlightedDate((DateTime)cells[0].Value, rowColour));
                for (int j = 0; j < this.Rows[i].Cells.Count; j++)
                {
                    this.Rows[i].Cells[j].Style.BackColor = rowColour;
                }
            }
            if (miniCalendar != null)
            {
                miniCalendar.updateColours(dates);
            }
        }


        private void this_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex != -1)
            {
                editRow(e.RowIndex);
            }
        }

        private void this_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if ((e.ColumnIndex == -1) && (e.RowIndex == -1))
            {
                editRow(-1);
            }
        }

        private void this_KeyUp(object sender, KeyEventArgs e)
        {
            if (keyDownFlag)
            {
                if (Keys.Insert.Equals(e.KeyCode))
                {
                    editRow(-1);
                }
                else if (Keys.Delete.Equals(e.KeyCode))
                {
                    if ((this.CurrentCell != null) && (this.CurrentCell.RowIndex != -1))
                    {
                        if (MessageBox.Show(this, confirmDeleteDialogText, confirmDeleteDialogCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2).Equals(DialogResult.Yes))
                        {
                            this.Rows.RemoveAt(this.CurrentCell.RowIndex);
                        }
                    }
                }
                else if (Keys.Enter.Equals(e.KeyCode))
                {
                    if ((this.CurrentCell != null) && (this.CurrentCell.RowIndex != -1))
                    {
                        editRow(this.CurrentCell.RowIndex);
                    }

                }
            }
            keyDownFlag = false;
        }

        private void this_KeyDown(object sender, KeyEventArgs e)
        {
            if ((Keys.Enter.Equals(e.KeyCode)) || (Keys.Delete.Equals(e.KeyCode)) || (Keys.Insert.Equals(e.KeyCode)))
            {
                e.Handled = true;
                keyDownFlag = true;
            }
        }

        private void editRow(int rowNo)
        {
            RowDataEditor editor = editorFactory.createRowDataEditor();
            RowData sr = getRowDataFromCellsRow(rowNo);
            sr = editor.ShowDialog(sr);
            putRowDataInRow(sr, rowNo);
            updateColours();
        }

        public void addRowData(RowData rd)
        {
            this.putRowDataInRow(rd, -1);
        }

        private void putRowDataInRow(RowData sr, int row)
        {
            if (sr != null)
            {
                object[] cells = sr.getDataForRow();
                if (row == -1)
                {       
                    this.Rows.Add(cells);
                }
                else
                {
                    for (int i = 0; i < cells.Length; i++)
                    {
                        this.Rows[row].Cells[i].Value = cells[i];
                    }
                }
            }
        }

        private RowData getRowDataFromCellsRow(int row)
        {
            RowData result = new RowData(DefaultWorkTimeHours, DefaultWorkTimeMinutes);
            if ((row >= 0) && (row < this.Rows.Count))
            {
                result = (RowData)this.Rows[row].Cells[5].Value;
                result.ActiveField = this.CurrentCell.ColumnIndex;
            }
            return result;
        }

        private System.Windows.Forms.DataGridViewTextBoxColumn ColumnDate;
        private System.Windows.Forms.DataGridViewTextBoxColumn ColumnTime;
        private System.Windows.Forms.DataGridViewTextBoxColumn ColumnDescription1;
        private System.Windows.Forms.DataGridViewTextBoxColumn ColumnDescription2;
        private System.Windows.Forms.DataGridViewTextBoxColumn ColumnDescription3;
        private System.Windows.Forms.DataGridViewTextBoxColumn ColumnModified;
 

    }
}
